//#include <QtCore>
//#include <QtCore/QCoreApplication>
//#include </usr/include/qt4/Qt/qimage.h>
//#include </usr/include/qt4/Qt/qcolor.h>
//#include <QString>
//#include <stdio.h>
//#include <iostream>
//#include <iomanip>
//#include <fstream>
//#include <string>
//#include <cmath>
//#include <math.h>
//#include <stdlib.h>

#include "Correlation.h"
#include "Data.h"
#include "RunTest.h"
#include "test/Test.h"


/* ----- Function declaration ----------------------------------------------------------------------------------------*/


/* ----- Initialize --------------------------------------------------------------------------------------------------*/

Correlation c;
Data d;
RunTest r;
Test t;
int sCountGlobal = 0;
int fCountGlobal = 0;


/*
  The purpose of this function is to rigorously test the correlation class.

  This function:

    1. Allows user to select which test(s) to perform           ex:  cin >> whichTest;
    2. Loads appropriate data into a correlation object         ex:  d.analyzeImage(testNumber, &c);
    3. Runs the requested test(s)                               ex:  r.analyzeImage(testNumber, &c, &d, &t);
    4. Displays the test results                                ex:  t.reportStatus("analyzeImage() test suite 0");

  The structure of the testing program involves four objects from different classes which the main() function calls
  to do the low-level work of performing tests. The following is an explanation of the role of each class:

    correlation - Contains the digital image correlation algorithms. The goal is to test all functions belonging to
      this class.
    data - Contains functions which load test data into (a) the correlation object, and (b) itself. This is done
      prior to a test of the function inside the correlation class.
    runTest - First, this class executes the function in the correlation object, using data stored in (a) the
      correlation object, and (b) the data object. Second, this class compares the function output with the
      expected output. The expected output is stored in the data object.
    test - This class provides functions which standardize the process of comparing expected with actual values. It
      contains generic functions which "assert" that two data sets are equivalent. These functions can optionally
      be used by the runTest class for standardized data comparison, especially when comparing arrays and images.

   Note that the naming convention is simply to give functions and variables inside the data and runTest classes the
   corresponding names in the correlation class. For example, to compare the value of epsxx[i] in the correlation class,
   compare  c.epsxx[i]  with  d.epsxx[i]

   Note: Be careful!! The naming convention can cause confusion. When referring to a member of a class, ensure that it
   belongs to the correct class.
  */
int main()
{
    /* ----- Request user selection of test(s) -----------------------------------------------------------------------*/

    int whichTest(-1);
    int counter(-1);
    cout << endl;
    cout << " " << counter++ << " - Run all tests. Show all results, followed by a summary of all test cases" << endl;
    cout << "   " << counter++ << " - Test the Test class" << endl;
    cout << "   " << counter++ << " - correlation()" << endl;
    // Level 0 Functions
    cout << "   " << counter++ << " - analyzeImage()" << endl;
    cout << "   " << counter++ << " - storePositionField()" << endl;
    cout << "   " << counter++ << " - storeStrainField()" << endl;
    cout << "   " << counter++ << " - outputImage()" << endl;
    cout << "   " << counter++ << " - outputOverlay()" << endl;
    // Level 1 Functions
    cout << "   " << counter++ << " - inputImage()" << endl;
    cout << "   " << counter++ << " - blobAnalysis()" << endl;
    cout << "   " << counter++ << " - extractPositionField()" << endl;
    cout << "   " << counter++ << " - generateGridMap()" << endl;
    cout << "   " << counter++ << " - computeStrain()" << endl;
    cout << "   " << counter++ << " - drawCurrentState()" << endl;
    // Level 2 Functions
    cout << "   " << counter++ << " - subsetImage()" << endl;
    cout << "   " << counter++ << " - filterImage()" << endl;
    cout << "   " << counter++ << " - matchBlob()" << endl;
    cout << "   " << counter++ << " - updateBoundingBox()" << endl;
    cout << "   " << counter++ << " - mergeBlobs()" << endl;
    cout << "   " << counter++ << " - postProcess()" << endl;
    cout << "   " << counter++ << " - blobProbability()" << endl;
    cout << "   " << counter++ << " - identifyDots()" << endl;
    cout << "   " << counter++ << " - isValidPointSet()" << endl;
    cout << "   " << counter++ << " - localStrain()" << endl;
    cout << "   " << counter++ << " - minIgnore()" << endl;
    cout << "   " << counter++ << " - maxIgnore()" << endl;
    cout << "   " << counter++ << " - drawBlobProperty()" << endl;
    cout << "   " << counter++ << " - drawCurrentPixel()" << endl;
    cout << "   " << counter++ << " - debugHandle()" << endl;
    cout << endl;
    cout << "Which test would you like to run? ";
    cin >> whichTest;
    cout << endl;


    /* ----- Execute requested tests ---------------------------------------------------------------------------------*/

    // Note: Four objects exist effectively, although not technically, in a global sense. This is achieved by
    //   passing pointers to certain member functions. Thus member parameters of the "global" objects are modified.
    //
    // Note: The precise order for a suite of tests is:
    //   1. Reset the test object
    //   2. Load data into the data object (which in some instances also automatically loads data into the
    //        correlation object)
    //   3. Run one or more member functions of the runTest object (this typically outputs individual test results)
    //   4. Display results of test suite by calling test::reportStatus()
    switch(whichTest) {
    case -1:


//        // Set global success/failure tracking variables
//        sCountGlobal = 0;
//        fCountGlobal = 0;

//        // Run all tests
//        r.testTest(whichTest);
//        r.testCconstructor(whichTest);
//        r.inputImage(whichTest);
//        r.generateGridMap(whichTest);
//        r.computeStrain(whichTest);
//        r.minIgnore(whichTest);
//        r.maxIgnore(whichTest);
//        r.localStrain(whichTest);
//        r.isValidPointSet(whichTest);

//        // Report success/failure ratio for entire test suite
//        t.resetTracking();
//        for(int s = 0; s < sCountGlobal; ++s) {
//            t.isEqual(1,1);
//        }
//        for(int f = 0; f < fCountGlobal; ++f) {
//            t.isEqual(1,2);
//        }
//        t.reportStatus("Results for all tests");

        break;
    case 0:
        t.resetTracking();
        r.testTest(whichTest, &c, &d, &t);
        t.reportStatus("Summary of all tests of the test class");
        break;
    case 1:
        t.resetTracking();
        d.correlationConstructor(whichTest, &c);
        r.correlationConstructor(whichTest, &c, &d, &t);
        t.reportStatus("correlation()");
        break;
    case 2:
        char testSuiteName[40];
        string testSuiteNameStr = "";
        for(int testNumber = 0; testNumber < 9; ++testNumber) {
            d.analyzeImage(testNumber, &c);
            r.analyzeImage(testNumber, &c, &d, &t);
            sprintf(testSuiteName, "analyzeImage() test suite %u", testNumber);
            testSuiteNameStr = testSuiteName;
            t.reportStatus(testSuiteNameStr);
        }

//        d.analyzeImage(4, &c);
//        r.analyzeImage(whichTest, &c, &d, &t);
        break;
//    case 3:
//        r.storePositionField(whichTest, &c, &d, &t);
//        break;
//    case 4:
//        r.storeStrainField(whichTest, &c, &d, &t);
//        break;
//    case 5:
//        r.outputImage(whichTest, &c, &d, &t);
//        break;
//    case 6:
//        r.outputOverlay(whichTest, &c, &d, &t);
//        break;
//    case 7:
//        r.inputImage(whichTest, &c, &d, &t);
//        break;
//    case 8:
//        r.blobAnalysis(whichTest, &c, &d, &t);
//        break;
//    case 9:
//        r.extractPositionField(whichTest, &c, &d, &t);
//        break;
//    case 10:
//        r.generateGridMap(whichTest, &c, &d, &t);
//        break;
//    case 11:
//        r.computeStrain(whichTest, &c, &d, &t);
//        break;
//    case 12:
//        r.drawCurrentState(whichTest, &c, &d, &t);
//        break;
//    case 13:
//        r.subsetImage(whichTest, &c, &d, &t);
//        break;
//    case 14:
//        r.filterImage(whichTest, &c, &d, &t);
//        break;
//    case 15:
//        r.matchBlob(whichTest, &c, &d, &t);
//        break;
//    case 16:
//        r.updateBoundingBox(whichTest, &c, &d, &t);
//        break;
//    case 17:
//        r.mergeBlobs(whichTest, &c, &d, &t);
//        break;
//    case 18:
//        r.postProcess(whichTest, &c, &d, &t);
//        break;
//    case 19:
//        r.blobProbability(whichTest, &c, &d, &t);
//        break;
//    case 20:
//        r.identifyDots(whichTest, &c, &d, &t);
//        break;
//    case 21:
//        r.isValidPointSet(whichTest, &c, &d, &t);
//        break;
//    case 22:
//        r.localStrain(whichTest, &c, &d, &t);
//        break;
//    case 23:
//        r.minIgnore(whichTest, &c, &d, &t);
//        break;
//    case 24:
//        r.maxIgnore(whichTest, &c, &d, &t);
//        break;
//    case 25:
//        r.drawBlobProperty(whichTest, &c, &d, &t);
//        break;
//    case 26:
//        r.drawCurrentPixel(whichTest, &c, &d, &t);
//    case 27:
//        r.debugHandle(whichTest, &c, &d, &t);
//        break;
    }






////        r.testConstructor(whichTest);
//        break;
//    case 2:
////        r.testInputImage(whichTest);
//        break;
//    case 3:
////        r.testGenerateGridMap(whichTest);
//        break;
//    case 4:
////        r.testComputeStrain(whichTest);
//        break;
//    case 5:
////        r.testMinIgnore(whichTest);
////        r.testMaxIgnore(whichTest);
//        break;
//    case 6:
////        r.testLocalStrain(whichTest);
//        break;
//    case 7:
////        r.testIsValidPointSet(whichTest);
//        break;
//    }


    /* ----- End program ---------------------------------------------------------------------------------------------*/
    cout << endl;
    cout << "Program finished." << endl;
    return 0;
}
